var timer = require('../../core/timer');
var util = require('../../util/index');
var Log = require('../../util/logger');
var fmod = require('fmod');
var _inited = false;
var _numTracks = 2;

/**
 * 设计:
 * editor的fmod是基于唯一一条track的, 创建出来audio对象, 也是为了加入track而准备的
 * 但audio也具备独立播放, 不加入track的能力
 * audio每加入一次track, 都会产生一个channel, 这个channel由调用者自行维护
 */

var ret = {
	fmod: fmod, //临时的播放直接调fmod对应方法, 自行控制
	init: function(){
		if(_inited){
			return;
		}
		this.cache = {};
		this.seekTimer = null;
		fmod.init();
		for (var i = 0; i < _numTracks; i++) {
			fmod.createTrack();
		}
		fmod.selectTrack(0);

		this.maxLength = 60000;
		fmod.setLenTrack(this.maxLength);
		this.fastSeekTime = NaN;
		this.speed = 1;

		this.offsetTime = NaN;
		var bufLength = fmod.getBufLength();
		// todo: sysUnstable表示底层音频的额外不稳定度。这是Windows上的值，Mac不详
		var sysUnstable = 10;
		var resyncTolerance = 33;
		this.stableTolerance = [
			-(bufLength + sysUnstable) * 0.5 - resyncTolerance,
			-(bufLength + sysUnstable) * 0.5,
			(bufLength + sysUnstable) * 0.5,
			(bufLength + sysUnstable) * 0.5 + resyncTolerance
		];

		timer.registUpdate(this.onUpdate.bind(this), 60);
		_inited = true;
	},

	release: function(){
		if(_inited){
			fmod.destroy();
		}
		_inited = false;
	},

	onUpdate: function(){
		fmod.update();
	},

	/**
	 * 设置虚拟时间最大长度
	 * @param len
	 */
	setMaxLength: function(len){
		this.maxLength = len;
		fmod.selectTrack(0);
		fmod.setLenTrack(len);
	},

	getMaxLength: function() {
		return this.maxLength;
	},

	/**
	 * 在load 之后, module内部使用id为key, 不用再查找
	 * 在明确不再使用sound的场合, 用unload卸载
	 */
	load: function(filename){
		var sound = this.cache[filename];
		if(typeof sound != 'undefined'){
			fmod.selectAudio(sound);
			return sound;
		}
		var id = fmod.loadAudio(filename);
		if(id >= 0){
			this.cache[filename] = id;
			return id;
		}else{
			Log.e("Failed to load "+filename, "Audio");
		}
		return -1;
	},

	/**
	 * 同时支持传name 和 id
	 */
	unload: function (filename) {
		var sound;
		if(typeof filename == 'string'){
			sound = this.cache[filename];
		}else if(typeof filename == 'number'){
			for(var key in this.cache){
				if(!this.cache.hasOwnProperty(key)){
					continue;
				}
				if(this.cache[key] == filename){
					sound = this.cache[key];
					filename = key;
					break;
				}
			}
		}
		if(typeof sound == 'undefined'){
			return;
		}
		fmod.selectAudio(sound);
		fmod.unloadAudio();
		delete this.cache[filename];
	},

	unloadAll: function(){
		for(var key in this.cache){
			if(!this.cache.hasOwnProperty(key)){
				continue;
			}
			var sound = this.cache[key];
			fmod.selectAudio(sound);
			fmod.unloadAudio();
		}
		this.cache = {};
	},

	rawTime: function () {
		fmod.selectTrack(0);
		return fmod.timeTrack();
	},

	stableTime: function() {
		var stableAudioTime;
		if (this.isPlaying()) {
			var runTime = window.performance.now();
			var audioTime = this.rawTime() / this.speed;
			var dt = (runTime - this.offsetTime) - audioTime;
			if (dt < this.stableTolerance[0]) {
				this.offsetTime = runTime - audioTime - this.stableTolerance[1];
			} else if (dt > this.stableTolerance[3]) {
				this.offsetTime = runTime - audioTime - this.stableTolerance[2];
			} else if (dt < this.stableTolerance[1]) {
				this.offsetTime += (dt - this.stableTolerance[1]) * 0.3;
			} else if (dt > this.stableTolerance[2]) {
				this.offsetTime += (dt - this.stableTolerance[2]) * 0.3;
			}
			stableAudioTime = (runTime - this.offsetTime) * this.speed;
		} else {
			stableAudioTime = this.rawTime();
		}

		if (isNaN(this.fastSeekTime)) {
			return stableAudioTime;
		} else {
			return this.fastSeekTime;
		}
	},

	resetStableTime: function() {
		var runTime = window.performance.now();
		var audioTime = this.rawTime() / this.speed;
		this.offsetTime = runTime - audioTime;
	},

	fastSeek: function(time){
		if(time < 0){
			time = 0;
		}else if(time > this.maxLength){
			time = this.maxLength;
		}
		//mac上有弹性滚动...
		if(Math.abs(time - this.fastSeekTime) < 10){
			return;
		}
		this.fastSeekTime = time;
		clearTimeout(this.seekTimer);
		var self = this;
		this.seekTimer = setTimeout(function(){
			self.completeSeek();
		}, 400);
	},

	completeSeek: function() {
		if (!isNaN(this.fastSeekTime)) {
			this.seekTo(this.fastSeekTime);
			this.fastSeekTime = NaN;
			this.resetStableTime();
		}
	},

	seekTo: function(time){
		if(time < 0){
			time = 0;
		}else if(time > this.maxLength){
			time = this.maxLength;
		}
		fmod.selectTrack(0);
		fmod.seekTrack(time);
	},

	isPlaying: function() {
		fmod.selectTrack(0);
		return fmod.isPlayingTrack();
	},

	play: function() {
		clearTimeout(this.seekTimer);
		this.completeSeek();
		fmod.selectTrack(0);
		fmod.playTrack();
		this.resetStableTime();
	},

	pause: function() {
		this.completeSeek();
		fmod.selectTrack(0);
		fmod.pauseTrack();
	},

	stop: function() {
		fmod.selectTrack(0);
		fmod.pauseTrack();
		fmod.seekTrack(0);
		this.fastSeekTime = NaN;
	},

	setSpeed: function(speed) {
		this.speed = speed;
		fmod.selectTrack(0);
		fmod.speedTrack(speed);
		this.resetStableTime();
	},

	toggle: function() {
		clearTimeout(this.seekTimer);
		this.completeSeek();
		fmod.selectTrack(0);
		fmod.toggleTrack();
	},

	clearTrack: function() {
		fmod.selectTrack(0);
		fmod.clearTrack();
	},

	addCell: function(filename, vol, offset) {
		fmod.selectTrack(0);
		var id = this.load(filename);
		var tid = fmod.addCell();
		fmod.volumeCell(vol);
		fmod.offsetCell(offset);
		return tid;
	},

	removeCell: function(tid) {
		fmod.selectTrack(0);
		fmod.selectCell(tid);
		fmod.removeCell();
	},

	volumeCell: function(tid, vol) {
		fmod.selectTrack(0);
		fmod.selectCell(tid);
		fmod.volumeCell(vol);
	},

	offsetCell: function(tid, offset) {
		fmod.selectTrack(0);
		fmod.selectCell(tid);
		fmod.offsetCell(offset);
	}
};

module.exports = ret;